<!DOCTYPE html>
<html lang="en">
<head>

    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />

    <title>RotaJakiro: A long live secret backdoor with 0 VT detection</title>
    <meta name="HandheldFriendly" content="True" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

    <link rel="stylesheet" type="text/css" href="/assets/built/screen.css?v=db215a41fd" />

    <link rel="shortcut icon" href="/favicon.png" type="image/png" />
    <link rel="canonical" href="https://blog.netlab.360.com/stealth_rotajakiro_backdoor_en/" />
    <meta name="referrer" content="no-referrer-when-downgrade" />
    <link rel="amphtml" href="https://blog.netlab.360.com/stealth_rotajakiro_backdoor_en/amp/" />
    
    <meta property="og:site_name" content="360 Netlab Blog - Network Security Research Lab at 360" />
    <meta property="og:type" content="article" />
    <meta property="og:title" content="RotaJakiro: A long live secret backdoor with 0 VT detection" />
    <meta property="og:description" content="Overview
On March 25, 2021, 360 NETLAB&#x27;s BotMon system flagged a suspiciousELF file
(MD5&#x3D;64f6cfe44ba08b0babdd3904233c4857) with 0 VT detection, the sample
communicates with 4 domains on TCP 443 (HTTPS), but the traffic is not of
TLS/SSL. A close look at the sample revealed it to be a backdoor  targeting
Linux X64 systems, a family that has been around for at least 3 years.

We named it RotaJakiro  based on the fact that the family uses rotate encryption
and behaves differently for root/non-root " />
    <meta property="og:url" content="https://blog.netlab.360.com/stealth_rotajakiro_backdoor_en/" />
    <meta property="article:published_time" content="2021-04-28T13:29:37.000Z" />
    <meta property="article:modified_time" content="2021-04-29T06:11:11.000Z" />
    <meta property="article:tag" content="Botnet" />
    <meta property="article:tag" content="New Threat" />
    <meta property="article:tag" content="Backdoor" />
    
    <meta name="twitter:card" content="summary" />
    <meta name="twitter:title" content="RotaJakiro: A long live secret backdoor with 0 VT detection" />
    <meta name="twitter:description" content="Overview
On March 25, 2021, 360 NETLAB&#x27;s BotMon system flagged a suspiciousELF file
(MD5&#x3D;64f6cfe44ba08b0babdd3904233c4857) with 0 VT detection, the sample
communicates with 4 domains on TCP 443 (HTTPS), but the traffic is not of
TLS/SSL. A close look at the sample revealed it to be a backdoor  targeting
Linux X64 systems, a family that has been around for at least 3 years.

We named it RotaJakiro  based on the fact that the family uses rotate encryption
and behaves differently for root/non-root " />
    <meta name="twitter:url" content="https://blog.netlab.360.com/stealth_rotajakiro_backdoor_en/" />
    <meta name="twitter:label1" content="Written by" />
    <meta name="twitter:data1" content="Alex.Turing" />
    <meta name="twitter:label2" content="Filed under" />
    <meta name="twitter:data2" content="Botnet, New Threat, Backdoor" />
    <meta name="twitter:site" content="@360Netlab" />
    <meta name="twitter:creator" content="@TuringAlex" />
    
    <script type="application/ld+json">
{
    "@context": "https://schema.org",
    "@type": "Article",
    "publisher": {
        "@type": "Organization",
        "name": "360 Netlab Blog - Network Security Research Lab at 360",
        "logo": "https://blog.netlab.360.com/content/images/2019/02/netlab-brand-5.png"
    },
    "author": {
        "@type": "Person",
        "name": "Alex.Turing",
        "image": {
            "@type": "ImageObject",
            "url": "https://blog.netlab.360.com/content/images/2019/06/turing.PNG",
            "width": 1363,
            "height": 1363
        },
        "url": "https://blog.netlab.360.com/author/alex/",
        "sameAs": [
            "https://twitter.com/TuringAlex"
        ]
    },
    "headline": "RotaJakiro: A long live secret backdoor with 0 VT detection",
    "url": "https://blog.netlab.360.com/stealth_rotajakiro_backdoor_en/",
    "datePublished": "2021-04-28T13:29:37.000Z",
    "dateModified": "2021-04-29T06:11:11.000Z",
    "keywords": "Botnet, New Threat, Backdoor",
    "description": "Overview\nOn March 25, 2021, 360 NETLAB&#x27;s BotMon system flagged a suspiciousELF file\n(MD5&#x3D;64f6cfe44ba08b0babdd3904233c4857) with 0 VT detection, the sample\ncommunicates with 4 domains on TCP 443 (HTTPS), but the traffic is not of\nTLS/SSL. A close look at the sample revealed it to be a backdoor  targeting\nLinux X64 systems, a family that has been around for at least 3 years.\n\nWe named it RotaJakiro  based on the fact that the family uses rotate encryption\nand behaves differently for root/non-root ",
    "mainEntityOfPage": {
        "@type": "WebPage",
        "@id": "https://blog.netlab.360.com/"
    }
}
    </script>

    <script src="/public/ghost-sdk.min.js?v=db215a41fd"></script>
<script>
ghost.init({
	clientId: "ghost-frontend",
	clientSecret: "2a7213b591a9"
});
</script>
    <meta name="generator" content="Ghost 2.13" />
    <link rel="alternate" type="application/rss+xml" title="360 Netlab Blog - Network Security Research Lab at 360" href="https://blog.netlab.360.com/rss/" />
    
<script>
  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

  ga('create', 'UA-83587830-1', 'auto');
  ga('send', 'pageview');

</script>

<!-- Fix first paragraph font size -->
<style type="text/css">
 .post-template .post-content > p:first-child {font-size: 1em;}
</style>

</head>
<body class="post-template tag-botnet tag-new-threat tag-backdoor">

    <div class="site-wrapper">

             <header
    class="site-header outer">
    <div class="inner">
        <nav class="site-nav">
    <div class="site-nav-left">
                <a class="site-nav-logo" href="https://blog.netlab.360.com"><img src="https://blog.netlab.360.com/content/images/2019/02/netlab-brand-5.png" alt="360 Netlab Blog - Network Security Research Lab at 360" /></a>
            <ul class="nav" role="menu">
    <li class="nav-botnet" role="menuitem"><a href="https://blog.netlab.360.com/tag/botnet/">Botnet</a></li>
    <li class="nav-dnsmon" role="menuitem"><a href="https://blog.netlab.360.com/tag/dnsmon/">DNSMon</a></li>
    <li class="nav-ddos" role="menuitem"><a href="https://blog.netlab.360.com/tag/ddos/">DDoS</a></li>
    <li class="nav-passivedns" role="menuitem"><a href="https://blog.netlab.360.com/tag/pdns/">PassiveDNS</a></li>
    <li class="nav-marai" role="menuitem"><a href="https://blog.netlab.360.com/tag/mirai/">Marai</a></li>
    <li class="nav-dta" role="menuitem"><a href="https://blog.netlab.360.com/tag/dta/">DTA</a></li>
</ul>

    </div>
    <div class="site-nav-right">
        <div class="social-links">
                <a class="social-link social-link-tw" href="https://twitter.com/360Netlab" title="Twitter" target="_blank" rel="noopener"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="M30.063 7.313c-.813 1.125-1.75 2.125-2.875 2.938v.75c0 1.563-.188 3.125-.688 4.625a15.088 15.088 0 0 1-2.063 4.438c-.875 1.438-2 2.688-3.25 3.813a15.015 15.015 0 0 1-4.625 2.563c-1.813.688-3.75 1-5.75 1-3.25 0-6.188-.875-8.875-2.625.438.063.875.125 1.375.125 2.688 0 5.063-.875 7.188-2.5-1.25 0-2.375-.375-3.375-1.125s-1.688-1.688-2.063-2.875c.438.063.813.125 1.125.125.5 0 1-.063 1.5-.25-1.313-.25-2.438-.938-3.313-1.938a5.673 5.673 0 0 1-1.313-3.688v-.063c.813.438 1.688.688 2.625.688a5.228 5.228 0 0 1-1.875-2c-.5-.875-.688-1.813-.688-2.75 0-1.063.25-2.063.75-2.938 1.438 1.75 3.188 3.188 5.25 4.25s4.313 1.688 6.688 1.813a5.579 5.579 0 0 1 1.5-5.438c1.125-1.125 2.5-1.688 4.125-1.688s3.063.625 4.188 1.813a11.48 11.48 0 0 0 3.688-1.375c-.438 1.375-1.313 2.438-2.563 3.188 1.125-.125 2.188-.438 3.313-.875z"/></svg>
</a>
        </div>
            <a class="rss-button" href="https://feedly.com/i/subscription/feed/https://blog.netlab.360.com/rss/" title="RSS" target="_blank" rel="noopener"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><circle cx="6.18" cy="17.82" r="2.18"/><path d="M4 4.44v2.83c7.03 0 12.73 5.7 12.73 12.73h2.83c0-8.59-6.97-15.56-15.56-15.56zm0 5.66v2.83c3.9 0 7.07 3.17 7.07 7.07h2.83c0-5.47-4.43-9.9-9.9-9.9z"/></svg>
</a>
    </div>
</nav>
    </div>
    </header>


    <main id="site-main" class="site-main outer">
        <div class="inner">

            <article class="post-full post tag-botnet tag-new-threat tag-backdoor no-image">

                <header class="post-full-header">
                    <section class="post-full-meta">
                        <time class="post-full-meta-date" datetime="2021-04-28">28 April                            2021</time>
                        <span class="date-divider">/</span> <a href="/tag/botnet/">Botnet</a>
                    </section>
                    <h1 class="post-full-title">RotaJakiro: A long live secret backdoor with 0 VT detection</h1>
                </header>


                <section class="post-full-content">
                    <div class="post-content">
                        <h2 id="overview">Overview</h2>
<p>On March 25, 2021,  360 NETLAB's BotMon system flagged a suspiciousELF file (MD5=64f6cfe44ba08b0babdd3904233c4857) with 0 VT detection, the sample communicates with 4 domains on TCP 443 (HTTPS), but the traffic is not of TLS/SSL. A close look at the sample revealed it to be a <strong>backdoor</strong> targeting Linux X64 systems, a family that has been around for <strong>at least 3 years</strong>.</p>
<p>We named it <strong>RotaJakiro</strong> based on the fact that the family uses rotate encryption and behaves differently for <code>root/non-root accounts</code> when executing.</p>
<p><code>RotaJakiro</code> pays quite some attention to hide its trails,  using multiple of encryption algorithms, including: the use of AES algorithm to encrypt the resource information within the sample; C2 communication using a combination of <code>AES, XOR, ROTATE encryption</code> and <code>ZLIB compression</code>.</p>
<p><code>RotaJakiro</code> supports a total of 12 functions, three of which are related to the execution of specific Plugins. Unfortunately, we have no visibilityto the plugins, and therefore do not know its true purpose. From a broad backdoor perspective, the functions can be grouped into the following four categories.</p>
<ul>
<li>Reporting device information</li>
<li>Stealing sensitive information</li>
<li>File/Plugin management (query, download, delete)</li>
<li>Execution of specific Plugin</li>
</ul>
<h2 id="anymoreoutthere">Any more out there?</h2>
<p>With the sample we have, we discovered the following 4 samples, all of which have 0 detections on VT, and the earliest First Seen time on VT is in 2018.</p>
<table>
<thead>
<tr>
<th>FileName</th>
<th>MD5</th>
<th>Detection</th>
<th>First Seen in VT</th>
</tr>
</thead>
<tbody>
<tr>
<td>systemd-daemon</td>
<td>1d45cd2c1283f927940c099b8fab593b</td>
<td>0/61</td>
<td>2018-05-16 04:22:59</td>
</tr>
<tr>
<td>systemd-daemon</td>
<td>11ad1e9b74b144d564825d65d7fb37d6</td>
<td>0/58</td>
<td>2018-12-25 08:02:05</td>
</tr>
<tr>
<td>systemd-daemon</td>
<td>5c0f375e92f551e8f2321b141c15c48f</td>
<td>0/56</td>
<td>2020-05-08 05:50:06</td>
</tr>
<tr>
<td>gvfsd-helper</td>
<td>64f6cfe44ba08b0babdd3904233c4857</td>
<td>0/61</td>
<td>2021-01-18 13:13:19</td>
</tr>
</tbody>
</table>
<p>These samples all have the following 4 C2s embedded. These 4 C2 domains have very close <code>Crteated,Updated and Expired</code> time, readers will notice that the crated data was in Dec 2015, 6 years ago.</p>
<table>
<thead>
<tr>
<th>Domain</th>
<th>Detection</th>
<th>Created</th>
<th>Last Updated</th>
<th>Expired</th>
</tr>
</thead>
<tbody>
<tr>
<td>news.thaprior.net</td>
<td>0/83</td>
<td>2015-12-09 06:24:13</td>
<td>2020-12-03 07:24:33</td>
<td>2021-12-09 06:24:13</td>
</tr>
<tr>
<td>blog.eduelects.com</td>
<td>0/83</td>
<td>2015-12-10 13:12:52</td>
<td>2020-12-03 07:24:33</td>
<td>2021-12-10 13:12:52</td>
</tr>
<tr>
<td>cdn.mirror-codes.net</td>
<td>0/83</td>
<td>2015-12-09 06:24:19</td>
<td>2020-12-03 07:24:32</td>
<td>2021-12-09 06:24:19</td>
</tr>
<tr>
<td>status.sublineover.net</td>
<td>0/83</td>
<td>2015-12-09 06:24:24</td>
<td>2020-12-03 07:24:32</td>
<td>2021-12-09 06:24:24</td>
</tr>
</tbody>
</table>
<h2 id="reverseanalysis">Reverse Analysis</h2>
<p>The 4 RotaJakiro samples, with time distribution from 2018 to 2021, are very close to their functions, and the 2021 sample is selected for analysis in this blog, which has the following basic information:</p>
<pre><code>MD5:64f6cfe44ba08b0babdd3904233c4857
ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, stripped
Packer:No
</code></pre>
<p><code>At the coding level</code>, RotaJakiro uses techniques such as dynamic AES, double-layer encrypted communication protocols to counteract the binary &amp; network traffic analysis.<br>
<code>At the functional level</code>, RotaJakiro first determines whether the user is root or non-root at run time, with different execution policies for different accounts, then decrypts the relevant sensitive resources using AES&amp; ROTATE for subsequent <code>persistence</code>, <code>process guarding</code> and <code>single instance</code> use, and finally establishes communication with C2 and waits for the execution of commands issued by C2.</p>
<p>The following will analyze the specific implementation of RotaJakiro from the above perspective.</p>
<h2 id="0x00tricksusedbythesample">0x00: Tricks used by the sample</h2>
<ul>
<li>Dynamically generate a table of constants required by the AES encryption algorithm to prevent the algorithm from being directly identified<br>
<img src="https://blog.netlab.360.com/content/images/2021/04/jak_dynaes.png" width="860px"></li>
<li>Use stack strings obfuscation technique to store encrypted sensitive resource information<br>
<img src="https://blog.netlab.360.com/content/images/2021/04/jak_stack.png" width="860px"></li>
<li>Network communication using double layer encryption</li>
</ul>
<h2 id="0x01encryptionalgorithm">0x01: Encryption algorithm</h2>
<p>All sensitive resources in RotaJakiro are encrypted, and in IDA we can see that the decryption method <strong>dec_proc</strong> is called 60 times, which is composed of AES and Rotate.<br>
<img src="https://blog.netlab.360.com/content/images/2021/04/jak_dec.png" width="860px"><br>
The AES decryption entry is as follows:<br>
<img src="https://blog.netlab.360.com/content/images/2021/04/jak_aes.png" width="860px"><br>
Where <code>aes_dec</code> is AES-256, CBC mode, key&amp;iv are hardcoded.</p>
<ul>
<li>KEY</li>
</ul>
<pre><code> 14 BA EE 23 8F 72 1A A6 00 00 00 00 00 00 00 00 
 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
</code></pre>
<ul>
<li>IV</li>
</ul>
<pre><code>  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
</code></pre>
<p>The Rotate decryption entry is shown below:<br>
<img src="https://blog.netlab.360.com/content/images/2021/04/jak_rota.png" width="860px"><br>
The so-called Rotate is a cyclic shift, we can see that the number of shifts is determined by the value of <code>plain_len(length of plaintext) &amp;7</code>.</p>
<p>Take the following C2 cipher text as an example.</p>
<pre><code>ff ba a2 3b cd 5b 7b 24 8c 5f e3 4b fc 56 5b 99 
ac 91 cf e3 9a 27 d4 c9 6b 39 34 ce 69 ce 18 60
</code></pre>
<p>The various parameters related to decryption are shown below, the length of the ciphertext is 32 bytes and the length of the plaintext is 26 bytes.<br>
<img src="https://blog.netlab.360.com/content/images/2021/04/jak_exp.png" width="860px"><br>
<strong>First</strong>, decrypting with AES, we get the following &quot;sub-ciphertext&quot;.<br>
<img src="https://blog.netlab.360.com/content/images/2021/04/jak_valid.png" width="860px"><br>
<strong>Then</strong>, the valid ciphertext is extracted from the  sub-ciphertext, where the valid ciphertext starts from the 8th byte, and the length is the plaintext length minus 8, which is 26-8=18 bytes here.</p>
<pre><code>98 1B DB D9 8B 59 19 5D 59 1B 59 D8 1D DC 8B D8 
DB 5B
</code></pre>
<p><strong>Finally</strong>, we can calculate 26(the length of plaintext is 26)&amp;7=2, and get the number of shifts, and shift the above valid ciphertext byte by byte by 2 bits to get C2 plaintext.</p>
<pre><code>blog.eduelects.com
</code></pre>
<h2 id="0x02persistence">0x02: Persistence</h2>
<p>RotaJakiro makes a distinction between <code>root/non-root</code> users when implementing persistence features, and different techniques are used for different accounts.</p>
<h3 id="rootaccount">root account</h3>
<ul>
<li>
<p>Depending on the Linux distribution, create the corresponding self-starting script <code>/etc/init/systemd-agent.conf</code> or <code>/lib/systemd/system/sys-temd-agent.service</code>.</p>
<pre><code>Content of systemd-agent.conf
-----------------------------
#system-daemon - configure for system daemon
#This service causes system have an associated
#kernel object to be started on boot.
description &quot;system daemon&quot;
start on filesystem or runlevel [2345]
exec /bin/systemd/systemd-daemon
respawn 
</code></pre>
<pre><code>Content of systemd-agent.service
-----------------------------
[Unit]
Description=System Daemon
Wants=network-online.target
After=network-online.target
[Service]
ExecStart=/usr/lib/systemd/systemd-daemon
Restart=always
[Install]
</code></pre>
</li>
<li>
<p>The file name used for the disguise is one of the following twos.</p>
<pre><code>/bin/systemd/systemd-daemon
/usr/lib/systemd/systemd-daemon
</code></pre>
</li>
</ul>
<h3 id="nonrootaccount">non-root account</h3>
<ul>
<li>Create autostart script<code>$HOME/.config/au-tostart/gnomehelper.desktop</code> for <strong>desktop environment</strong><pre><code>[Desktop Entry]
Type=Application
Exec=$HOME/.gvfsd/.profile/gvfsd-helper
</code></pre>
</li>
<li>Modify the <code>.bashrc</code> file to create the autostart script for the <strong>shell environment</strong><pre><code># Add GNOME's helper designed to work with the I/O abstraction of GIO
# this environment variable is set, gvfsd will not start the fuse filesystem
if [ -d ${HOME} ]; then
        ${HOME}/.gvfsd/.profile/gvfsd-helper
fi
</code></pre>
</li>
<li>The file name used for the disguise, both of which exist at the same time<pre><code>$HOME/.dbus/sessions/session-dbus
$HOME/.gvfsd/.profile/gvfsd-helper
</code></pre>
</li>
</ul>
<h2 id="0x03processguarding">0x03:Process guarding</h2>
<p>RotaJakiro implements process guarding to protect its own operation, and like persistence, there are different implementations for <code>root/non-root</code> users.</p>
<h3 id="rootaccount">root account</h3>
<p>When running under the root account, depending on the Linux distribution, a new process is automatically created when the service process is terminated by writing <code>Restart=always or respawn</code> to the service's configuration file.<br>
<img src="https://blog.netlab.360.com/content/images/2021/04/jak_rootcfg.png" width="860px"><br>
The actual result is shown in the figure below, where you can see that a new process is created immediately after the systemd-daemon process is terminated.<br>
<img src="https://blog.netlab.360.com/content/images/2021/04/jak_rootprot.png" width="860px"></p>
<h3 id="nonrootaccount">non-root account</h3>
<p>When running under a non-root account, RotaJakiro generates two processes, <code>session-dbus</code> and <code>gvfsd-helper</code>, which monitor each other's survival and restore them when one of them is terminated, which is very typical of dual-process protection.</p>
<p>How is RotaJakiro's dual-process protection implemented?</p>
<p><strong>First</strong>, it creates a piece of shared memory with the <code>shmget API</code>, and session-dbus and gvfsd-helper communicate with each other through this shared memory, telling each other their PIDs.<br>
<strong>Then</strong>, dynamically fetching the process survival through the <code>/proc/[PID]</code> directory. When the other process is found dead, the process is created by <strong>execvp</strong> API to help the dead process &quot;resurrect&quot;, as shown in the following diagram.<br>
<img src="https://blog.netlab.360.com/content/images/2021/04/jak_monitor.png" width="860px"><br>
The actual effect is shown in the figure below, you can see that after session-dbus and gvfsd-helper are ended by kill -9, new processes are created right away.<br>
<img src="https://blog.netlab.360.com/content/images/2021/04/jak_nonrprot.png" width="860px"></p>
<h2 id="0x04singleinstance">0x04: Single instance</h2>
<p>RotaJakiro implements a single instance by file locking, as shown below.<br>
<img src="https://blog.netlab.360.com/content/images/2021/04/jak_single.png" width="860px"><br>
The lockfile used in this differs under the root/non-root account.</p>
<ul>
<li>The lockfile under root, one will be created.<pre><code>/usr/lib32/.X11/X0-lock
/bin/lib32/.X11/X0-lock
</code></pre>
</li>
<li>The lockfile under non-root, both will be created.<pre><code>$HOME/.X11/X0-lock
$HOME/.X11/.X11-lock
</code></pre>
</li>
</ul>
<p>In the actual non-root account, for example, the processes and file locks can be matched by <code>/proc/locks</code>, and then the corresponding RotaJakiro sample is executed.<br>
<img src="https://blog.netlab.360.com/content/images/2021/04/jak_instance.png" width="860px"></p>
<h2 id="0x05networkcommunication">0x05: Network communication</h2>
<p>RotaJakiro establishes communication with C2 through the following code snippet, pending the execution of subsequent commands.<br>
<img src="https://blog.netlab.360.com/content/images/2021/04/jak_stage.png" width="860px"><br>
This process can be divided into 2 stages</p>
<ul>
<li>Stage 1, initialization phase<br>
Decrypt the C2 list, establish a connection with C2, send the online information, receive and decrypt the information returned by C2.</li>
<li>Stage 2, wait for C2 calls<br>
Verify the information returned by C2, if it passes the verification, execute the subsequent instructions sent by C2.</li>
</ul>
<h3 id="stage1initialization">Stage 1: Initialization</h3>
<p>The C2 list is decrypted by the decryption algorithm described in the previous section, and the following four C2s are built into the sample at present.</p>
<pre><code>news.thaprior.net
blog.eduelects.com
cdn.mirror-codes.net
status.sublineover.net
</code></pre>
<p>RotaJakiro will first try to establish a connection with them, and then construct the golive message by the following code snippet.<br>
<img src="https://blog.netlab.360.com/content/images/2021/04/jak_cons.png" width="860px"><br>
Then it encrypts the golive information and sends it to the C2s<br>
<img src="https://blog.netlab.360.com/content/images/2021/04/jak_xor.png" width="860px"><br>
Finally, it receives the packet back from the C2, decrypts it and checks its legitimacy, and if it passes the check, it goes to Stage 2.<br>
<img src="https://blog.netlab.360.com/content/images/2021/04/jak_recvreg.png" width="860px"></p>
<h3 id="stage2specificoperations">Stage 2: Specific operations</h3>
<p>Receive and execute the command from C2 through the following codesnippet.<br>
<img src="https://blog.netlab.360.com/content/images/2021/04/jak_stage2.png" width="860px"><br>
At present, RotaJakiro supports a total of 12 instructions, and the correspondence between the instruction code and the function is shown in the following table.</p>
<table>
<thead>
<tr>
<th>CmdId</th>
<th>Function</th>
</tr>
</thead>
<tbody>
<tr>
<td>0x138E3E6</td>
<td>Exit</td>
</tr>
<tr>
<td>0x208307A</td>
<td>Test</td>
</tr>
<tr>
<td>0x5CCA727</td>
<td>Heartbeat</td>
</tr>
<tr>
<td>0x17B1CC4</td>
<td>Set C2 timeout time</td>
</tr>
<tr>
<td>0x25360EA</td>
<td>Steal Senstive Info</td>
</tr>
<tr>
<td>0x18320e0</td>
<td>Upload Device Info</td>
</tr>
<tr>
<td>0x2E25992</td>
<td>Deliver File/Plugin</td>
</tr>
<tr>
<td>0x2CD9070</td>
<td>Query File/Plugin Status</td>
</tr>
<tr>
<td>0x12B3629</td>
<td>Delete File/Plugin Or Dir</td>
</tr>
<tr>
<td>0x1B25503</td>
<td>Run Plugin_0x39C93E</td>
</tr>
<tr>
<td>0x1532E65</td>
<td>Run Plugin_0x75A7A2</td>
</tr>
<tr>
<td>0x25D5082</td>
<td>Run Plugin_0x536D01</td>
</tr>
</tbody>
</table>
<p>The <strong>Run Plugin</strong> function reuses the same code and implements the function call through the following logic.<br>
<img src="https://blog.netlab.360.com/content/images/2021/04/jak_plugin.png" width="860px"><br>
We are currently not capturing such payloads, so we use the <code>Plugin_&quot;parameter&quot;</code> form to represent different tasks.</p>
<h2 id="0x06packetanalysis">0x06 Packet analysis</h2>
<p>The network communication packet of RotaJakiro consists of three parts: <code>Head, Key, Payload</code>.<br>
<img src="https://blog.netlab.360.com/content/images/2021/04/jak_packet.png" width="860px"><br>
<code>Head</code> is mandatory and 82 bytes long, and the <code>Key &amp; Payload</code> parts are optional.<br>
<code>Head &amp; Key</code>are encrypted with XOR &amp; Rotate, and <code>Payload</code> is encrypted with AES &amp; ZLIB Compression.<br>
In the following, we will illustrate the composition of network traffic <code>head&amp;key&amp;payload</code> and the decryption process through a round of interaction between Bot and C2.</p>
<h3 id="c2bot">C2 -&gt; Bot</h3>
<img src="https://blog.netlab.360.com/content/images/2021/04/jak_cmd.png" width="860px">
<p>The first 0x52 bytes are the content of the Head. How to decrypt the head? Very simple, <code>shift 3 bits left byte by byte, and then XOR with 0x1b</code>. After decryption, we can get the following content.</p>
<pre><code>00000000  16 11 10 b9 03 b1 0c fb 04 20 00 00 00 08 00 e0  |...¹.±.û. .....à|
00000010  20 83 01 c2 20 64 20 01 e2 00 00 00 00 c2 0c 00  | ..Â d .â....Â..|
00000020  00 00 32 42 36 39 33 33 34 46 38 34 31 44 30 44  |..2B69334F841D0D|
00000030  39 46 41 30 36 35 38 45 43 33 45 32 39 46 41 44  |9FA0658EC3E29FAD|
00000040  34 39 c8 53 e6 9c 48 c4 8b 77 24 2e 02 1c 96 d9  |49ÈSæ.HÄ.w$....Ù|
00000050  81 28
------------filed parse------------------
offset 0x09, 4 bytes---&gt;payload length
offset 0x0d, 2 bytes---&gt;body length
offset ox0f, 4 bytes---&gt;cmdid
</code></pre>
<p>Through the field parsing, we can know that the length of key is 0x8 bytes, the length of payload is 0x20 bytes, and the instruction code to be executed is 0x18320e0, that is, the <code>report device information</code>.Reading 8 bytes from offset 0x52 gives the <strong>Key</strong><code>ea 9a 1a 18 18 44 26 a0</code>, and using the same decryption method as head, we get <code>4c cf cb dbdb 39 2a 1e</code>, which is used as the AES key to decrypt the Payload.</p>
<p>Reading 32 bytes from offset 0x5a gives us the following <strong>Payload</strong>.</p>
<pre><code>54 c1 c3 69 00 18 31 e4 a2 5b 10 7f 67 ab d1 4b 
b2 7b 3d 3f b3 bc 66 6a 26 f6 f6 b3 f7 2e 66 6d
</code></pre>
<p>Using the decrypted key as the AES-256 key, decrypt the above data in CBC mode to get the following content.</p>
<pre><code>3b c7 f8 9b 73 2b d1 04 78 9c e3 60 60 60 d8 df d9 c1 71 56 f7 6f 00 00 13 80 04 28
</code></pre>
<p>The 8th byte onwards is ZLIB compressed data, decompressed to get the following content.</p>
<pre><code>08 00 00 00 bf 89 88 08 cd 2d fd 50
------------filed parse------------------
offset 0, 4 bytes---&gt;length
</code></pre>
<p>What is the use of the decompressed Payload(<code>bf 89 88 08 cd 2d fd 50</code>)? It is used as <strong>a new AES key to decrypt some sensitive resource information</strong>.</p>
<p>For example, when Bot collects device information, one of the information is the current OS distribution, which is implemented by the <code>cat /etc/*release | uniq</code> command.</p>
<pre><code>root@debian:~# cat /etc/*release | uniq
PRETTY_NAME=&quot;Debian GNU/Linux 9 (stretch)&quot;
NAME=&quot;Debian GNU/Linux&quot;
VERSION_ID=&quot;9&quot;
VERSION=&quot;9 (stretch)&quot;
ID=debian
HOME_URL=&quot;https://www.debian.org/&quot;
SUPPORT_URL=&quot;https://www.debian.org/support&quot;
BUG_REPORT_URL=&quot;https://bugs.debian.org/&quot;
</code></pre>
<p>The<code>cat /etc/*release | uniq</code> command  is the result of the following cipher text</p>
<pre><code>&quot;cat /etc/*release | uniq&quot; cmd_ciphertxt
---------------------------
74 00 dd 79 e6 1e aa bb 99 81 7e ca d9 21 6b 81 
6b d9 9d 14 45 73 6a 1c 61 cc 28 a3 0f 2b 41 5a 
6b 33 8c 37 25 89 47 05 44 7e f0 6b 17 70 d8 ca
</code></pre>
<p>decrypted with the <code>new AES key and the parameters</code> in the following figure.<br>
<img src="https://blog.netlab.360.com/content/images/2021/04/jak_paykey.png" width="860px"></p>
<h3 id="botc2">Bot -&gt; C2</h3>
<p>When BOT receives C2's &quot;report device information&quot; command, it will send the following data to C2, and you can see that the value of the key part is still <code>ea 9a 1a 18 18 44 26 a0</code>.<br>
<img src="https://blog.netlab.360.com/content/images/2021/04/jak_payload.png" width="860px"><br>
The decrypted key value is <code>4c cf cb db db 39 2a 1e</code>. After decrypting and decompressing the payload sent by Bot to C2, we get the following data, which is the various information of the device, including the information obtained by <code>cat /etc/*release | uniq</code>mentioned before, which verifies that our analysis is correct.<br>
<img src="https://blog.netlab.360.com/content/images/2021/04/jak_device-1.png" width="860px"></p>
<h2 id="relationshipwiththetoriibotnet">Relationship with the Torii Botnet</h2>
<p>The <a href="https://blog.avast.com/new-torii-botnet-threat-research">Torii botnet</a> was exposed by Avast on September 20, 2018, and we noticed that there are some the similarities between the twos,for example:</p>
<h4 id="1stringsimilarity">1: String similarity</h4>
<p>After decrypting the sensitive resources of RotaJakiro &amp; Torii, we found that they reuse a lot of the same commands.</p>
<pre><code>1：semanage fcontext -a -t bin_t '%s' &amp;&amp; restorecon '%s'
2：which semanage
3：cat /etc/*release 
4：cat /etc/issue
5：systemctl enable
6：initctl start
...
</code></pre>
<h4 id="2trafficsimilarity">2: Traffic similarity</h4>
<p>In the process of constructing the flow, a large number of constants are used and the construction methods are very close.<br>
<img src="https://blog.netlab.360.com/content/images/2021/04/jak_compare.png" width="860px"></p>
<h4 id="3functionalsimilarity">3: Functional similarity</h4>
<p>From the perspective of reverse engineering, RotaJakiro &amp; Torii share similar styles: the use of encryption algorithms to hide sensitive resources, the implementation of a rather old-school style of persistence,structured network traffic, etc.</p>
<p>We don’t exactly know the answer, but it seems that RotaJakiro and Torii have some connections.</p>
<h2 id="thetipoftheiceberg">The tip of the iceberg</h2>
<p>While this concludes our analysis of RotaJakiro, the real work is far from over, and many questions remain unanswered: &quot;How did RotaJakiro spread, and what was its purpose?&quot; , &quot;Does RotaJakiro have a specific target?”, We would love to know if the community has relevant leads.</p>
<h2 id="contactus">Contact us</h2>
<p>Readers are always welcomed to reach us on <a href="https://twitter.com/360Netlab"><strong>twitter</strong></a>, or email to <strong>netlabat[at]360.cn</strong>.</p>
<h2 id="ioc">IOC</h2>
<p>Sample MD5</p>
<pre><code>1d45cd2c1283f927940c099b8fab593b
11ad1e9b74b144d564825d65d7fb37d6
5c0f375e92f551e8f2321b141c15c48f
64f6cfe44ba08b0babdd3904233c4857
</code></pre>
<p>C2</p>
<pre><code>news.thaprior.net:443
blog.eduelects.com:443
cdn.mirror-codes.net:443
status.sublineover.net:443
</code></pre>
<p>IP</p>
<pre><code>176.107.176.16 Ukraine|Kiev|Unknown 42331|PE_Freehost
</code></pre>

                    </div>
                </section>


                <footer class="post-full-footer">


                    <section class="post-full-authors">

    <div class="post-full-authors-content">
        <p>This post was a collaboration between</p>
        <p><a href="/author/alex/">Alex.Turing</a>, <a href="/author/huiwang/">Hui Wang</a></p>
    </div>

    <ul class="author-list">
        <li class="author-list-item">

            <div class="author-card">
                <div class="basic-info">
                        <img class="author-profile-image" src="https://blog.netlab.360.com/content/images/size/w100/2019/06/turing.PNG" alt="Alex.Turing" />
                    <h2>Alex.Turing</h2>
                </div>
                <div class="bio">
                        <p>Read <a href="/author/alex/">more posts</a> by this author.</p>
                </div>
            </div>

                <a href="/author/alex/" class="moving-avatar">
                    <img class="author-profile-image" src="https://blog.netlab.360.com/content/images/size/w100/2019/06/turing.PNG" alt="Alex.Turing" />
                </a>

        </li>
        <li class="author-list-item">

            <div class="author-card">
                <div class="basic-info">
                        <img class="author-profile-image" src="https://blog.netlab.360.com/content/images/size/w100/2017/05/WechatIMG1.jpeg" alt="Hui Wang" />
                    <h2>Hui Wang</h2>
                </div>
                <div class="bio">
                        <p>Read <a href="/author/huiwang/">more posts</a> by this author.</p>
                </div>
            </div>

                <a href="/author/huiwang/" class="moving-avatar">
                    <img class="author-profile-image" src="https://blog.netlab.360.com/content/images/size/w100/2017/05/WechatIMG1.jpeg" alt="Hui Wang" />
                </a>

        </li>

    </ul>

</section>


                </footer>

                <div id="disqus_thread"></div>
                <script>
                    var disqus_config = function () {
                        this.page.url = "https://blog.netlab.360.com/stealth_rotajakiro_backdoor_en/";
                        this.page.identifier = "ghost-6088ce8d3819e500076335cb"
                    };
                    (function () {
                        var d = document, s = d.createElement('script');
                        s.src = 'https://blog-netlab-360.disqus.com/embed.js';
                        s.setAttribute('data-timestamp', +new Date());
                        (d.head || d.body).appendChild(s);
                    })();
                </script>

            </article>

        </div>
    </main>

    <aside class="read-next outer">
        <div class="inner">
            <div class="read-next-feed">
                <article class="read-next-card"   style="background-image: url(https://blog.netlab.360.com/content/images/size/w600/2019/02/astronomy-constellation-dark-998641-4.jpg)"
                     >
                    <header class="read-next-card-header">
                        <small class="read-next-card-header-sitetitle">&mdash; 360 Netlab Blog - Network Security Research Lab at 360 &mdash;</small>
                        <h3 class="read-next-card-header-title"><a href="/tag/botnet/">Botnet</a></h3>
                    </header>
                    <div class="read-next-divider"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M13 14.5s2 3 5 3 5.5-2.463 5.5-5.5S21 6.5 18 6.5c-5 0-7 11-12 11C2.962 17.5.5 15.037.5 12S3 6.5 6 6.5s4.5 3.5 4.5 3.5"/></svg>
</div>
                    <div class="read-next-card-content">
                        <ul>
                            <li><a href="/yi-jing-you-xxxge-jia-zu-de-botnetli-yong-log4shelllou-dong-chuan-bo-wei-da-bu-ding-de-gan-jin-liao/">已有10个家族的恶意样本利用Log4j2漏洞传播</a></li>
                            <li><a href="/threat-alert-log4j-vulnerability-has-been-adopted-by-two-linux-botnets/">Threat Alert: Log4j Vulnerability Has Been adopted by two Linux Botnets</a></li>
                            <li><a href="/wei-xie-kuai-xun-log4jlou-dong-yi-jing-bei-yong-lai-zu-jian-botnet-zhen-dui-linuxshe-bei/">威胁快讯：Log4j漏洞已经被用来组建botnet，针对Linux设备</a></li>
                        </ul>
                    </div>
                    <footer class="read-next-card-footer">
                        <a href="/tag/botnet/">See all 98 posts →</a>
                    </footer>
                </article>

                <article class="post-card post tag-sysrv tag-sysrv-hello tag-miner tag-crypto-mining tag-botnet tag-iframe tag-ldr-sh tag-a-py tag-browserupdate tag-xmrig tag-coinminer tag-ldr-ps1 no-image">


    <div class="post-card-content">

        <a class="post-card-content-link" href="/wei-xie-kuai-xun-z0miner-zheng-zai-li-yong-elasticsearch-he-jenkins-lou-dong-da-si-chuan-bo/">

            <header class="post-card-header">
                    <span class="post-card-tags">sysrv</span>
                <h2 class="post-card-title">威胁快讯：Sysrv-hello再次升级，通过感染网页文件提高传播能力</h2>
            </header>

            <section class="post-card-excerpt">
                <p>版权 版权声明: 本文为Netlab原创，依据 CC BY-SA 4.0 许可证进行授权，转载请附上出处链接及本声明。 概述 从去年末到现在，挖矿类型的botnet家族一直活跃，除了新家族不断出现，一些老家族也频繁升级，主要是为了提高传播能力和隐蔽性，我们的 BotMon 系统对此多有检测[rinfo][z0miner]。最新的案例来自Sysrv-hello，本来近期已经有2家安全公司先后分析过该家族的新变种[1][2]，但文章刚出来sysrv的作者就在4月20号再次进行升级，增加了感染网页的能力，本文对此做一分析。 新模块a.py和BrowserUpdate.exe 我们知道sysrv能同时感染Linux和Windows系统，其入口为一个脚本文件，</p>
            </section>

        </a>

        <footer class="post-card-meta">

            <ul class="author-list">
                <li class="author-list-item">

                    <div class="author-name-tooltip">
                        LIU Ya
                    </div>

                        <a href="/author/liu/" class="static-avatar author-profile-image"><svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><path d="M3.513 18.998C4.749 15.504 8.082 13 12 13s7.251 2.504 8.487 5.998C18.47 21.442 15.417 23 12 23s-6.47-1.558-8.487-4.002zM12 12c2.21 0 4-2.79 4-5s-1.79-4-4-4-4 1.79-4 4 1.79 5 4 5z" fill="#FFF"/></g></svg>
</a>
                </li>
                <li class="author-list-item">

                    <div class="author-name-tooltip">
                        YANG XU
                    </div>

                        <a href="/author/xuy1202/" class="static-avatar">
                            <img class="author-profile-image" src="https://blog.netlab.360.com/content/images/size/w100/2019/04/head.jpg" alt="YANG XU" />
                        </a>
                </li>
                <li class="author-list-item">

                    <div class="author-name-tooltip">
                        jinye
                    </div>

                        <a href="/author/jinye/" class="static-avatar">
                            <img class="author-profile-image" src="https://blog.netlab.360.com/content/images/size/w100/2019/12/400--2-.jpeg" alt="jinye" />
                        </a>
                </li>
            </ul>

            <span class="reading-time">4 min read</span>

        </footer>

    </div>

</article>

                <article class="post-card post tag-botnet tag-new-threat tag-backdoor no-image">


    <div class="post-card-content">

        <a class="post-card-content-link" href="/stealth_rotajakiro_backdoor_cn/">

            <header class="post-card-header">
                    <span class="post-card-tags">Botnet</span>
                <h2 class="post-card-title">双头龙(RotaJakiro)，一个至少潜伏了3年的后门木马</h2>
            </header>

            <section class="post-card-excerpt">
                <p>版权 版权声明：本文为Netlab原创，依据 CC BY-SA 4.0 许可证进行授权，转载请附上出处链接及本声明。 概述 2021年3月25日，360 NETLAB的BotMon系统发现一个的VT 0检测的可疑ELF文件(MD5=64f6cfe44ba08b0babdd3904233c4857)，它会与4个业务类型截然不同的域名进行通信，端口均为TCP 443（HTTPS），但流量却并非TLS/SSL类型，这个异常行为引起了我们的兴趣，进一步分析发现它是一个针对Linux X64系统的后门木马，该家族至少已经存在3年但目前还是0检测。基于该家族使用rotate加密，并且运行后对root/non-root账户有不同的行为，犹如一只双头龙，一体双向，我们将它命名为RotaJakiro。</p>
            </section>

        </a>

        <footer class="post-card-meta">

            <ul class="author-list">
                <li class="author-list-item">

                    <div class="author-name-tooltip">
                        Alex.Turing
                    </div>

                        <a href="/author/alex/" class="static-avatar">
                            <img class="author-profile-image" src="https://blog.netlab.360.com/content/images/size/w100/2019/06/turing.PNG" alt="Alex.Turing" />
                        </a>
                </li>
                <li class="author-list-item">

                    <div class="author-name-tooltip">
                        Hui Wang
                    </div>

                        <a href="/author/huiwang/" class="static-avatar">
                            <img class="author-profile-image" src="https://blog.netlab.360.com/content/images/size/w100/2017/05/WechatIMG1.jpeg" alt="Hui Wang" />
                        </a>
                </li>
            </ul>

            <span class="reading-time">16 min read</span>

        </footer>

    </div>

</article>

            </div>
        </div>
    </aside>

    <div class="floating-header">
    <div class="floating-header-logo">
        <a href="https://blog.netlab.360.com">
                <img src="https://blog.netlab.360.com/content/images/size/w30/2019/02/netlab_xs-2.png" alt="360 Netlab Blog - Network Security Research Lab at 360 icon" />
            <span>360 Netlab Blog - Network Security Research Lab at 360</span>
        </a>
    </div>
    <span class="floating-header-divider">&mdash;</span>
    <div class="floating-header-title">RotaJakiro: A long live secret backdoor with 0 VT detection</div>
    <div class="floating-header-share">
        <div class="floating-header-share-label">Share this <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
    <path d="M7.5 15.5V4a1.5 1.5 0 1 1 3 0v4.5h2a1 1 0 0 1 1 1h2a1 1 0 0 1 1 1H18a1.5 1.5 0 0 1 1.5 1.5v3.099c0 .929-.13 1.854-.385 2.748L17.5 23.5h-9c-1.5-2-5.417-8.673-5.417-8.673a1.2 1.2 0 0 1 1.76-1.605L7.5 15.5zm6-6v2m-3-3.5v3.5m6-1v2"/>
</svg>
</div>
        <a class="floating-header-share-tw" href="https://twitter.com/share?text=RotaJakiro%3A%20A%20long%20live%20secret%20backdoor%20with%200%20VT%20detection&amp;url=https://blog.netlab.360.com/stealth_rotajakiro_backdoor_en/"
            onclick="window.open(this.href, 'share-twitter', 'width=550,height=235');return false;">
            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="M30.063 7.313c-.813 1.125-1.75 2.125-2.875 2.938v.75c0 1.563-.188 3.125-.688 4.625a15.088 15.088 0 0 1-2.063 4.438c-.875 1.438-2 2.688-3.25 3.813a15.015 15.015 0 0 1-4.625 2.563c-1.813.688-3.75 1-5.75 1-3.25 0-6.188-.875-8.875-2.625.438.063.875.125 1.375.125 2.688 0 5.063-.875 7.188-2.5-1.25 0-2.375-.375-3.375-1.125s-1.688-1.688-2.063-2.875c.438.063.813.125 1.125.125.5 0 1-.063 1.5-.25-1.313-.25-2.438-.938-3.313-1.938a5.673 5.673 0 0 1-1.313-3.688v-.063c.813.438 1.688.688 2.625.688a5.228 5.228 0 0 1-1.875-2c-.5-.875-.688-1.813-.688-2.75 0-1.063.25-2.063.75-2.938 1.438 1.75 3.188 3.188 5.25 4.25s4.313 1.688 6.688 1.813a5.579 5.579 0 0 1 1.5-5.438c1.125-1.125 2.5-1.688 4.125-1.688s3.063.625 4.188 1.813a11.48 11.48 0 0 0 3.688-1.375c-.438 1.375-1.313 2.438-2.563 3.188 1.125-.125 2.188-.438 3.313-.875z"/></svg>
        </a>
        <a class="floating-header-share-fb" href="https://www.facebook.com/sharer/sharer.php?u=https://blog.netlab.360.com/stealth_rotajakiro_backdoor_en/"
            onclick="window.open(this.href, 'share-facebook','width=580,height=296');return false;">
            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="M19 6h5V0h-5c-3.86 0-7 3.14-7 7v3H8v6h4v16h6V16h5l1-6h-6V7c0-.542.458-1 1-1z"/></svg>
        </a>
    </div>
    <progress id="reading-progress" class="progress" value="0">
        <div class="progress-container">
            <span class="progress-bar"></span>
        </div>
    </progress>
</div>




        <footer class="site-footer outer">
            <div class="site-footer-content inner">
                <section class="copyright"><a href="https://blog.netlab.360.com">360 Netlab Blog - Network Security Research Lab at 360</a> &copy; 2021</section>
                <nav class="site-footer-nav">
                    <a href="https://blog.netlab.360.com">Latest Posts</a>
                    
                    <a href="https://twitter.com/360Netlab" target="_blank" rel="noopener">Twitter</a>
                    <a href="https://ghost.org" target="_blank" rel="noopener">Ghost</a>
                </nav>
            </div>
        </footer>

    </div>


    <script>
        var images = document.querySelectorAll('.kg-gallery-image img');
        images.forEach(function (image) {
            var container = image.closest('.kg-gallery-image');
            var width = image.attributes.width.value;
            var height = image.attributes.height.value;
            var ratio = width / height;
            container.style.flex = ratio + ' 1 0%';
        })
    </script>


    <script
        src="https://code.jquery.com/jquery-3.2.1.min.js"
        integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4="
        crossorigin="anonymous">
    </script>
    <script type="text/javascript" src="/assets/built/jquery.fitvids.js?v=db215a41fd"></script>


    <script>
// Adds delay to author card dropups to disappear. This gives enough
// time for the user to interact with the author card while they move
// the mouse from the avatar to the card. Also makes space for the
// interacted avatar.
$(document).ready(function () {

    var hoverTimeout;

    $('.author-list-item').hover(function(){
        var $this = $(this);

        clearTimeout(hoverTimeout);

        $('.author-card').removeClass('hovered');
        $(this).children('.author-card').addClass('hovered');

    }, function() {
        var $this = $(this);

        hoverTimeout = setTimeout(function() {
            $this.children('.author-card').removeClass('hovered');
        }, 800);
    });

});
</script>

    <script>

        // NOTE: Scroll performance is poor in Safari
        // - this appears to be due to the events firing much more slowly in Safari.
        //   Dropping the scroll event and using only a raf loop results in smoother
        //   scrolling but continuous processing even when not scrolling
        $(document).ready(function () {
            // Start fitVids
            var $postContent = $(".post-full-content");
            $postContent.fitVids();
            // End fitVids

            var progressBar = document.querySelector('#reading-progress');
            var header = document.querySelector('.floating-header');
            var title = document.querySelector('.post-full-title');

            var lastScrollY = window.scrollY;
            var lastWindowHeight = window.innerHeight;
            var lastDocumentHeight = $(document).height();
            var ticking = false;

            function onScroll() {
                lastScrollY = window.scrollY;
                requestTick();
            }

            function onResize() {
                lastWindowHeight = window.innerHeight;
                lastDocumentHeight = $(document).height();
                requestTick();
            }

            function requestTick() {
                if (!ticking) {
                    requestAnimationFrame(update);
                }
                ticking = true;
            }

            function update() {
                var trigger = title.getBoundingClientRect().top + window.scrollY;
                var triggerOffset = title.offsetHeight + 35;
                var progressMax = lastDocumentHeight - lastWindowHeight;

                // show/hide floating header
                if (lastScrollY >= trigger + triggerOffset) {
                    header.classList.add('floating-active');
                } else {
                    header.classList.remove('floating-active');
                }

                progressBar.setAttribute('max', progressMax);
                progressBar.setAttribute('value', lastScrollY);

                ticking = false;
            }

            window.addEventListener('scroll', onScroll, { passive: true });
            window.addEventListener('resize', onResize, false);

            update();

        });
    </script>


    

</body>
</html>
